package com.hw8;

import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.model.GetObjectRequest;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.region.Region;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 腾讯云cos CosService
 *
 * @author wei.yong
 */
@Slf4j
@Component
public class CosServiceImpl implements CosService {

    //腾讯云cos存储 url
    @Value("${tencent.cos.url}")
    protected String tencentCosUrl;
    //腾讯云cos存储 存储桶
    @Value("${tencent.cos.bucketName}")
    protected String tencentCosBucketName;

    //腾讯云cos存储 唯一资源标识
    @Value("${tencent.cos.appId}")
    protected String tencentCosAppId;

    //腾讯云cos存储 身份识别id
    @Value("${tencent.cos.secretId}")
    protected String tencentCosSecretId;

    //腾讯云cos存储 身份密钥
    @Value("${tencent.cos.secretKey}")
    protected String tencentCosSecretKey;

    //腾讯云cos存储 地域信息
    @Value("${tencent.cos.region}")
    protected String tencentCosRegion;

    /**
     * 获取cos客户端
     * @return COSClient
     */
    protected COSClient getCosClient() {
        // 1 初始化用户身份信息（secretId, secretKey）。
        COSCredentials cred = new BasicCOSCredentials(tencentCosSecretId, tencentCosSecretKey);
        // 2 设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
        // clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
        Region region = new Region(tencentCosRegion);
        ClientConfig clientConfig = new ClientConfig(region);
        // 3 生成 cos 客户端。
        COSClient cosClient = new COSClient(cred, clientConfig);
        return cosClient;
    }

    public static Map<String, String> savePathMap = new HashMap<String, String>();

    static {
        savePathMap.put(CosConstants.FILE_TYPE_GAME, "/uploads/game/");
        savePathMap.put(CosConstants.FILE_TYPE_TOPIC, "/uploads/topic/");
        savePathMap.put(CosConstants.FILE_TYPE_TRADE, "/uploads/trade/");
        savePathMap.put(CosConstants.FILE_TYPE_BANNER, "/uploads/banner/");
        savePathMap.put(CosConstants.FILE_TYPE_AVATAR, "/uploads/avatar/");
        savePathMap.put(CosConstants.FILE_TYPE_AUTHENTICATION, "/uploads/authentication/");
        savePathMap.put(CosConstants.FILE_TYPE_WORKORDER, "/uploads/workOrder/");
        savePathMap.put(CosConstants.FILE_TYPE_MOMENT, "/uploads/moment/");
    }

    /**
     * cos上传
     *
     * @param bytes
     * @param originalFilename
     * @param type
     * @return Result<?>
     */
    @Override
    public String upload(byte[] bytes, String originalFilename, String type) {
        log.info("(CosService-upload)-传入参数, bytes:{}, originalFilename:{}, type:{}", bytes == null ? null : bytes.length, originalFilename, type);
        //指定要上传的文件
        File localFile = new File(originalFilename);
        try {
            FileUtils.writeByteArrayToFile(localFile, bytes);
        } catch (IOException e) {
            log.error("(CosService-upload)-写入文件异常, Exception = {}, message = {}", e, e.getMessage());
        }
        //获取文件原名
        // "/uploads/game/201907/"
        String saveDirPath = savePathMap.get(type) + new LocalDate().toString("yyyyMM");
        //文件名md5
        String fileName = DigestUtils.md5Hex(bytes) + CosConstants.DOT + FilenameUtils.getExtension(originalFilename);
        // "/uploads/game/201907/89660f7dac14c9c7f929135060a87853.png"
        String key = saveDirPath + "/" + fileName;

        COSClient cosClient = this.getCosClient();
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(tencentCosBucketName, key, localFile);
            PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
            String etag = putObjectResult.getETag();
            String requestId = putObjectResult.getRequestId();
            log.info("(CosService-upload)-上传到cos-返回, etag:{}, requestId:{}", etag, requestId);
        } catch (CosClientException e) {
            log.error("(CosService-upload)-上传到cos异常, Exception = {}, message = {}", e, e.getMessage());
        } finally {
            if (cosClient != null) {
                cosClient.shutdown();
            }
            //删除保存的临时文件
            FileUtils.deleteQuietly(localFile);
        }

        String url = tencentCosUrl + key;
        log.info("(CosService-upload)-返回结果, result:{}", url);
        return url;
    }

    /**
     * cos下载文件
     *
     * @param fileName
     * @param key
     * @return Result<?>
     */
    public Map<String, Object> download(String fileName, String key) {
        log.info("(CosService-download)-cos下载文件-传入参数, fileName:{}, key:{}", fileName, key);
        COSClient cosClient = this.getCosClient();

        Map<String, Object> rawMetadata = null;
        try {
            // 指定对象所在的存储桶
            // 指定要下载到的本地路径
            File downFile = new File(fileName);
            GetObjectRequest getObjectRequest = new GetObjectRequest(tencentCosBucketName, key);
            ObjectMetadata downObjectMeta = this.getCosClient().getObject(getObjectRequest, downFile);
            rawMetadata = downObjectMeta.getRawMetadata();
        } catch (CosClientException e) {
            log.error("(CosService-download)-cos下载文件异常, Exception = {}, message = {}", e, e.getMessage());
        } finally {
            if (cosClient != null) {
                cosClient.shutdown();
            }
        }

        return rawMetadata;
    }

    /**
     * cos删除文件
     *
     * @param key
     * @return Result<?>
     */
    public void delete(String key) {
        log.info("(CosService-delete)-cos删除文件-传入参数, key:{}", key);
        COSClient cosClient = this.getCosClient();
        try {
            this.getCosClient().deleteObject(tencentCosBucketName, key);
        } catch (CosClientException e) {
            log.error("(CosService-delete)-cos删除文件异常, Exception = {}, message = {}", e, e.getMessage());
        } finally {
            if (cosClient != null) {
                cosClient.shutdown();
            }
        }

    }

}